#include "renderwidget.h"

renderWidget::renderWidget(QWidget *parent) : QOpenGLWidget(parent)
{

}

renderWidget::~renderWidget()
{
    glDeleteTextures(3, m_textures);
}

void renderWidget::RendVideo(H264YUV_Frame *yuvFrame)
{
    if(yuvFrame == NULL ){
        return;
    }

    if(m_nVideoH != yuvFrame->height || m_nVideoW != yuvFrame->width){

        if(NULL != m_pBufYuv420p)
        {
            free(m_pBufYuv420p);
            m_pBufYuv420p=NULL;
        }
    }

    m_nVideoW =  yuvFrame->width;
    m_nVideoH = yuvFrame->height;

    m_yFrameLength = yuvFrame->luma.length;
    m_uFrameLength = yuvFrame->chromaB.length;
    m_vFrameLength = yuvFrame->chromaR.length;


    //申请内存存一帧yuv图像数据,其大小为分辨率的1.5倍
    int nLen = m_yFrameLength + m_uFrameLength +m_vFrameLength;

    if(NULL == m_pBufYuv420p)
    {
        m_pBufYuv420p = ( unsigned char*) malloc(nLen);
    }

    memcpy(m_pBufYuv420p,yuvFrame->luma.dataBuffer,m_yFrameLength);
    memcpy(m_pBufYuv420p+m_yFrameLength,yuvFrame->chromaB.dataBuffer,m_uFrameLength);
    memcpy(m_pBufYuv420p+m_yFrameLength +m_uFrameLength,yuvFrame->chromaR.dataBuffer,m_vFrameLength);


    m_bUpdateData =true;

    update();

}

void renderWidget::initializeGL()
{
    m_bUpdateData = false;

    initializeOpenGLFunctions();

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.0, 0.0, 0.0, 1.0);   //

    glGenTextures(3, m_textures);

    QOpenGLShader* vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, this);
    bool bCompileVS = vertexShader->compileSourceFile(":/shader/vertex.vert");
    if (!bCompileVS)
        qDebug()<<"VS Compile ERROR:"<<vertexShader->log();

    QOpenGLShader* fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment,this);
    bool bCompileFS = fragmentShader->compileSourceFile(":/shader/fragment.frag");
    if(bCompileFS == false){
        qDebug()<<"FS Compile ERROR:"<<fragmentShader->log();
    }

    m_pShaderProgram = new QOpenGLShaderProgram();
    m_pShaderProgram->addShader(vertexShader);
    m_pShaderProgram->addShader(fragmentShader);

    bool linkStatus = m_pShaderProgram->link();
    if(linkStatus == false){
        qDebug()<<"LINK ERROR:"<<m_pShaderProgram->log();
    }

    if(vertexShader){
        delete vertexShader;
        vertexShader = nullptr;
    }

    if(fragmentShader){
        delete fragmentShader;
        fragmentShader = nullptr;
    }
}

void renderWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void renderWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    if(m_bUpdateData == false){
        return;
    }

    static XH_Vertex triangleVert[] = {
        {-1, 1,  1,     0,0},
        {-1, -1,  1,    0,1},
        {1,  1,  1,     1,0},
        {1,  -1,  1,    1,1},
    };

    QMatrix4x4 matrix;
    matrix.ortho(-1,1,-1,1,0.1,1000);
    matrix.translate(0,0,-3);

    m_pShaderProgram->bind();

    m_pShaderProgram->setUniformValue("uni_mat",matrix);


    m_pShaderProgram->enableAttributeArray("attr_position");
    m_pShaderProgram->enableAttributeArray("attr_uv");

    m_pShaderProgram->setAttributeArray("attr_position",GL_FLOAT,triangleVert,3,sizeof(XH_Vertex));
    m_pShaderProgram->setAttributeArray("attr_uv",GL_FLOAT,&triangleVert[0].u,2,sizeof(XH_Vertex));

    m_pShaderProgram->setUniformValue("uni_textureY",0);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_textures[0]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW, m_nVideoH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pBufYuv420p);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    m_pShaderProgram->setUniformValue("uni_textureU",1);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, m_textures[1]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,m_nVideoW/2, m_nVideoH/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (char*)(m_pBufYuv420p+m_yFrameLength));
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    m_pShaderProgram->setUniformValue("uni_textureV",2);
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, m_textures[2]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW/2, m_nVideoH/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (char*)(m_pBufYuv420p+m_yFrameLength+m_uFrameLength));
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);


    m_pShaderProgram->disableAttributeArray("attr_position");
    m_pShaderProgram->disableAttributeArray("attr_uv");

    m_pShaderProgram->release();
}
